/**
 * Copyright 2010 Victor Egea Hernando
 *
 * RockScript is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 * 
 * RockScript is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with RockScript.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "routine.h"
#include "vm_macros.h"

#include <iostream>

#define ARGUMENT(MP,IDX) \
	(-(MP->_sfstack + SP_NO_LOCAL_EXP_REG) + IDX)

namespace paper{

routine::routine( corelib::uint32 id ){
    // set routine stack
    _stack = new __register[ssize];
    // set flags and counters
    _flags = _pc = _lock = 0; 
	// set stack pointer
	_rsp = _stack + 1;
	// ...
    _useful_sf = 0;
	_sp = (__register *) corelib::null;
    _ep = (__register *) corelib::null;
    // routine identification and state
    _id = id; _state = NEW;
    // set pointers to null
    _mp = corelib::null; 
}

routine::~routine(){
	delete _stack;
}

bool routine::alloc_frame( method &method ){
    // (size) ssfsize + arguments
    if( ( ( _rsp - _stack ) + method._sfstack + SP_NO_LOCAL_EXP_REG ) < ssize ){
        // refresh pointers
        _rsp += method._sfstack + SP_NO_LOCAL_EXP_REG;
        // save PC & MP
        _rsp[-1]._vp = _mp;
        _rsp[-2]._plain = _pc;
        // set new method pointer && program counter
        _mp = &method; _pc = _lock = 0;
        // check if the new method it's been compiled
        bool nm_jit = _mp->block().ready();
        // ...
        _sp = _rsp - SP_CONTEXT_REGS;
        _ep = _sp - _mp->_sfstack - SP_ARGUMENTS_THIS;
        _useful_sf = _mp->_sfstack + SP_ARGUMENTS_THIS;
        // room enough
        return( true );
    }
    // stack overflow
    return( false );
}

void routine::free_frame( void ){
    // check if the stack is not empty
    if( ( _rsp - _stack ) > 1 ){
		// get frame size
        corelib::uint32 fsize = _mp->_sfstack;
        // load PC & MP
        _mp    = (method*)_rsp[-1]._vp;
        _pc    = _rsp[-2]._plain;
        // free stack frame
        _rsp -= fsize + SP_NO_LOCAL_EXP_REG;
        // check stack size
        if( ( _rsp - _stack ) > 1 ){
            // ...
            _sp = _rsp - SP_CONTEXT_REGS;
            _ep = _sp - _mp->_sfstack - SP_ARGUMENTS_THIS;
            _useful_sf = _mp->_sfstack + SP_ARGUMENTS_THIS;
        }else{
        	// set state as terminated
            _state = TERMINATED;
        }
    }else{
        // set state as terminated
        _state = TERMINATED;
	}
}

void routine::backtrace( std::ostream &os ){
	os << "backtrace >>" << std::endl;

	corelib::uint32 idx = 0;
	__register *rsp = _rsp; method *mp = _mp;
    // check if the stack is not empty
    while( rsp - _stack > 1 ){
		// print method
		os << "   #" << (idx++) << " " << *mp << "(";
		os  << ");sp:" << (rsp - _stack) << std::endl;
		// decrease stack pointer & get new method pointer
        corelib::uint32 fsize = mp->_sfstack;
        mp = (method*)rsp[-1]._vp;
		rsp -= fsize + SP_NO_LOCAL_EXP_REG;
	}
}

}; // namespace paper;

